package net.hiapoe.gsnake4j.bean;

import java.awt.Toolkit;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.Random;

import javax.swing.JOptionPane;

import net.hiapoe.gsnake4j.listener.MainWinListener;
import net.hiapoe.gsnake4j.window.RunMe;

/**
 * 
 * @Author Administrator
 * @Description Snake类
 * @Version 1.0.3
 * @Date 2013年10月1日
 */
public class Snake implements Runnable {
	// 常量
	public final static int DEFAULT_LENGTH = 5;
	public final static int DEFAUTL_INTERVAL = 220;
	public final static int DEAD = 0;
	public final static int GOTFOOD = 1;
	public final static int GOTNOTHING = 2;
	public final static Random RANDOMer = new Random();
	public final static Object SNAKE_LOCKER = new Object();

	// 方向枚举
	public static enum Direction {
		UP(1), DOWN(-1), LEFT(2), RIGHT(-2);
		public final int value;

		private Direction(int value) {
			this.value = value;
		}
	};

	// 单实例
	private static Snake snake = null;
	// 状态信息, 当前食物
	private static Node currentfood = creatFood();
	private static long lastmoved = System.currentTimeMillis();
	private static long lastmovedbykey = MainWinListener
			.getLast_moved_times_by_key();
	// 最高分及相关信息
	private int record_point = 0;
	private long record_runtime = 0;
	private int record_times = 0;
	// Snake信息
	private int point = 0;
	private long runtime = 0;
	private int times = 0;
	private LinkedList<Node> nodes = new LinkedList<Node>();
	private Direction direction = Direction.UP;
	private Boolean isrunable = true;
	private int interval = DEFAUTL_INTERVAL;

	/*
	 * 私有构造
	 */
	private Snake() {
	}

	/*
	 * 获得单实例对象, 第一次调用时对其初始化
	 */
	public static synchronized Snake getInstance() {
		if (Snake.snake == null) {
			Snake.snake = new Snake();
			Snake.snake.initSnake();
		}
		return Snake.snake;
	}

	/*
	 * run方法
	 * 
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		while (true) {
			while (this.isrunable) {
				Snake.move();
				try {
					Thread.sleep(this.getInterval());
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	/*
	 * 初始化Snake对象
	 */
	private void initSnake() {
		synchronized (SNAKE_LOCKER) {
			nodes.clear();
			for (int i = 0; i < DEFAULT_LENGTH; i++) {
				nodes.add(new Node(10, 15 + i));
			}
		}
		this.direction = Direction.UP;
		this.interval = DEFAUTL_INTERVAL;
		this.isrunable = true;
		this.point = 0;
		this.runtime = 0;
		this.times += 1;
	}

	/*
	 * 单线程调用, 调用Snake移动及控制移动之后的操作
	 */
	public static void move(String... tag) {
		if (MainWinListener.isIs_key_sensitive()
				&& MainWinListener.getLast_moved_times_by_key() != lastmovedbykey) {
			if (!(tag.length == 1 && tag[0].equals(MainWinListener.TAG))) {
				lastmovedbykey = MainWinListener.getLast_moved_times_by_key();
				return;
			}
		}
		Snake.setLastmoved(System.currentTimeMillis());
		long runtime = Snake.getInstance().getRuntime();
		Snake.getInstance().setRuntime(
				runtime + Snake.getInstance().getInterval());
		int newsnakestatus = Snake.getInstance().catchFood();
		if (runtime <= 3599000 && newsnakestatus != Snake.DEAD) {
			if (newsnakestatus == Snake.GOTFOOD) {
				creatFood();
				Snake.getInstance().setPoint(
						Snake.getInstance().getPoint()
								+ (int) ((Snake.DEFAUTL_INTERVAL - 20
										+ Snake.DEFAUTL_INTERVAL - Snake
										.getInstance().getInterval()) * 0.05));
			}
		} else {
			Snake.getInstance().setIsrunable(false);
			Toolkit.getDefaultToolkit().beep();
			String formatedtime = (new SimpleDateFormat("mm分ss秒"))
					.format(runtime);
			String msg = "You guy lose!";
			if (runtime > 3599000) {
				msg += " You spend too much time!";
			}
			if (Snake.getInstance().getPoint() > Snake.getInstance()
					.getRecord_point()) {
				Snake.getInstance().setRecord_point(
						Snake.getInstance().getPoint());
				Snake.getInstance().setRecord_runtime(runtime);
				Snake.getInstance().setRecord_times(
						Snake.getInstance().getTimes());
				msg = "Congratulations! You break the record!";
			}
			if (JOptionPane.showConfirmDialog(RunMe.window.jframe, msg
					+ "\r\n局数: 第" + Snake.getInstance().getTimes()
					+ "局\r\n得分: " + Snake.getInstance().getPoint()
					+ "\r\n所用时间: " + formatedtime + "\r\n是否继续?", "提示",
					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.NO_OPTION) {
				System.exit(0);
			} else {
				reLive();
			}
		}
	}

	/*
	 * 控制Snake移动及移动后的Node
	 */
	private int catchFood() {
		Direction direction = this.direction;
		int re = Snake.GOTFOOD;
		Node nextnode = null;
		if (direction == Direction.UP) {
			nextnode = new Node(nodes.get(0).getX(), nodes.get(0).getY() - 1);
		} else if (direction == Direction.DOWN) {
			nextnode = new Node(nodes.get(0).getX(), nodes.get(0).getY() + 1);
		} else if (direction == Direction.LEFT) {
			nextnode = new Node(nodes.get(0).getX() - 1, nodes.get(0).getY());
		} else if (direction == Direction.RIGHT) {
			nextnode = new Node(nodes.get(0).getX() + 1, nodes.get(0).getY());
		}
		if (nextnode.getX() < 1 || nextnode.getX() > Drawer.MAX_NODE_NUM_X
				|| nextnode.getY() < 1
				|| nextnode.getY() > Drawer.MAX_NODE_NUM_Y
				|| nodes.contains(nextnode)) {
			re = Snake.DEAD;
		} else {
			synchronized (SNAKE_LOCKER) {
				nodes.add(0, nextnode);
				if (!nodes.contains(getCurrentfood())) {
					re = Snake.GOTNOTHING;
					nodes.removeLast();
				}
			}
		}
		return re;
	}

	/*
	 * 控制Snake复活并添加食物
	 */
	public static void reLive() {
		Snake.getInstance().initSnake();
		creatFood();
	}

	/*
	 * 创建食物, 如不和要求则递归
	 */
	private static Node creatFood() {
		int x = RANDOMer.nextInt(Drawer.MAX_NODE_NUM_X) + 1;
		int y = RANDOMer.nextInt(Drawer.MAX_NODE_NUM_Y) + 1;
		Node food = new Node(x, y);
		if (Snake.getInstance().getNodes().contains(food)) {
			return creatFood();
		}
		currentfood = food;
		return food;
	}

	/*
	 * 加速
	 */
	public void speedUp() {
		interval -= 20;
		if (interval < 20) {
			interval = 20;
		}
	}

	/*
	 * 减速
	 */
	public void speedDown() {
		interval += 20;
		if (interval > DEFAUTL_INTERVAL + 120) {
			interval = DEFAUTL_INTERVAL + 120;
		}
	}

	/*
	 * Gets and Sets
	 */
	public LinkedList<Node> getNodes() {
		return nodes;
	}

	public static Node getCurrentfood() {
		return currentfood;
	}

	// 自身调用

	public static long getLastmoved() {
		return lastmoved;
	}

	private static void setLastmoved(long lastmoved) {
		Snake.lastmoved = lastmoved;
	}

	// Drawer和this调用
	public int getRecord_point() {
		return record_point;
	}

	private void setRecord_point(int record_point) {
		this.record_point = record_point;
	}

	public long getRecord_runtime() {
		return record_runtime;
	}

	private void setRecord_runtime(long record_runtime) {
		this.record_runtime = record_runtime;
	}

	public int getRecord_times() {
		return record_times;
	}

	private void setRecord_times(int record_times) {
		this.record_times = record_times;
	}

	// Drawer和this调用
	public int getPoint() {
		return point;
	}

	public void setPoint(int point) {
		this.point = point;
	}

	public long getRuntime() {
		return runtime;
	}

	public void setRuntime(long runtime) {
		this.runtime = runtime;
	}

	public int getTimes() {
		return times;
	}

	public void setTimes(int times) {
		this.times = times;
	}

	// 监听器中调用
	public Direction getDirection() {
		return direction;
	}

	public void setDirection(Direction direction) {
		this.direction = direction;
	}

	public int getInterval() {
		return interval;
	}

	public void setInterval(int interval) {
		this.interval = interval;
	}

	public Boolean getIsrunable() {
		return isrunable;
	}

	public void setIsrunable(Boolean isrunable) {
		this.isrunable = isrunable;
	}
}
